package com.shoulder.log.aop;


import com.shoulder.core.api.ApiResult;
import com.shoulder.core.api.ApiToken;
import com.shoulder.core.api.ApiUser;
import com.shoulder.core.utils.JsonUtils;
import com.shoulder.core.utils.TokenUtils;
import com.shoulder.log.Log;
import com.shoulder.log.annotation.LogAnnotation;
import com.shoulder.log.event.LogEvent;
import com.shoulder.log.utils.IpUtils;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Aspect
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
@Slf4j
@AllArgsConstructor
public class LogAop {

    private final ApplicationEventPublisher eventPublisher;

    @Around("@annotation(com.shoulder.log.annotation.LogAnnotation)")
    public Object saveLog(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        //获取操作类型
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
        log.info("开始处理请求[{}:{}] ", logAnnotation.type(), request.getRequestURI());
        long start = System.currentTimeMillis();
        String agent = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(agent);
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        Log apiLog = new Log();
        apiLog.setTitle(logAnnotation.type());
        apiLog.setRequestUri(request.getRequestURI());
        apiLog.setIp(IpUtils.getIpAddress(request));
        apiLog.setDeviceType(operatingSystem.getName());
        apiLog.setClientType(request.getHeader("client-type"));
        //记录参数
        String[] parameterNames = methodSignature.getParameterNames();
        if (parameterNames != null && parameterNames.length > 0) {
            //获取参数的值
            Map<String, Object> params = new HashMap<>();
            Object[] args = joinPoint.getArgs();
            for (int i = 0; i < parameterNames.length; i++) {
                Object value = args[i];
                if (needRecord(value)) {
                    params.put(parameterNames[i], value);
                }
            }
            log.info("请求 [{}:{}] 的请求参数为:{}", logAnnotation.type(), request.getRequestURI(), JsonUtils.obj2Json(params));
            apiLog.setParams(JsonUtils.obj2Json(params));
        }

        Object result;
        try {
            result = joinPoint.proceed();
            apiLog.setResult("成功");
            apiLog.setResp(JsonUtils.obj2Json(result));
            //用户登录
            if (logAnnotation.isLogin()) {
                ApiUser apiUser = TokenUtils.parseUser(((ApiToken) ((ApiResult<?>) result).getData()).getAccessToken());
                apiLog.setNickname(apiUser.getNickname());
                apiLog.setTenantId(apiUser.getTenantId());
            }
            return result;
        } catch (Exception e) {
            apiLog.setResult("失败");
            throw e;
        } finally {
            long end = System.currentTimeMillis();
            apiLog.setCost(BigDecimal.valueOf(end - start));
            ApiUser loginUser;
            try {
                loginUser = TokenUtils.parseUser();
            } catch (Exception e) {
                loginUser = null;
            }
            if (loginUser != null) {
                apiLog.setNickname(loginUser.getNickname());
                apiLog.setTenantId(loginUser.getTenantId());
            }
            if (logAnnotation.record()) {
                log.info("记录请求 [{}:{}] 业务日志: {}", apiLog.getTitle(), apiLog.getRequestUri(), JsonUtils.obj2Json(apiLog));
                eventPublisher.publishEvent(new LogEvent(apiLog));
            }
            log.info("请求 [{}:{}] 处理结束,耗时: {} ms", logAnnotation.type(), request.getRequestURI(), apiLog.getCost());
        }

    }

    private boolean needRecord(Object value) {
        return !(value instanceof HttpServletRequest)
                && !(value instanceof HttpServletResponse)
                && !(value instanceof BindingResult);
    }
}